{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://www.rustwiki.org.cn/en/rust-by-example/hello.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "// This is a comment, and is ignored by the compiler\n",
    "// You can test this code by clicking the \"Run\" button over there ->\n",
    "// or if you prefer to use your keyboard, you can use the \"Ctrl + Enter\" shortcut\n",
    "\n",
    "// This code is editable, feel free to hack it!\n",
    "// You can always return to the original code by clicking the \"Reset\" button ->\n",
    "\n",
    "// This is the main function\n",
    "fn main() {\n",
    "    // Statements here are executed when the compiled binary is called\n",
    "\n",
    "    // Print text to the console\n",
    "    println!(\"Hello World!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World!\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`println!` is a [macro](https://www.rustwiki.org.cn/en/rust-by-example/macros.html) that prints text to the console."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A binary can be generated using the Rust compiler: `rustc`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "! $HOME/.cargo/bin/rustc ./hello.rs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World!\n"
     ]
    }
   ],
   "source": [
    "! ./hello"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "  println!(\"Hello World!\");\n",
    "  println!(\"I'm a Rustacean!\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello World!\n",
      "I'm a Rustacean!\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Comments](https://www.rustwiki.org.cn/en/rust-by-example/hello/comment.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://www.rustwiki.org.cn/en/rust-by-example/meta/doc.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any program requires comments, and Rust supports a few different varieties:\n",
    "\n",
    "Regular comments which are ignored by the compiler:\n",
    "- `// Line comments which go to the end of the line.`\n",
    "- `/* Block comments which go to the closing delimiter. */`\n",
    "\n",
    "Doc comments which are parsed into HTML library documentation:\n",
    "- `/// Generate library docs for the following item.`\n",
    "- `//! Generate library docs for the enclosing item.`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    // This is an example of a line comment\n",
    "    // There are two slashes at the beginning of the line\n",
    "    // And nothing written inside these will be read by the compiler\n",
    "\n",
    "    // println!(\"Hello, world!\");\n",
    "\n",
    "    // Run it. See? Now try deleting the two slashes, and run it again.\n",
    "\n",
    "    /* \n",
    "     * This is another type of comment, a block comment. In general,\n",
    "     * line comments are the recommended comment style. But\n",
    "     * block comments are extremely useful for temporarily disabling\n",
    "     * chunks of code. /* Block comments can be /* nested, */ */\n",
    "     * so it takes only a few keystrokes to comment out everything\n",
    "     * in this main() function. /*/*/* Try it yourself! */*/*/\n",
    "     */\n",
    "\n",
    "    /*\n",
    "    Note: The previous column of `*` was entirely for style. There's\n",
    "    no actual need for it.\n",
    "    */\n",
    "\n",
    "    // You can manipulate expressions more easily with block comments\n",
    "    // than with line comments. Try deleting the comment delimiters\n",
    "    // to change the result:\n",
    "    let x = 5 + /* 90 + */ 5;\n",
    "    println!(\"Is `x` 10 or 100? x = {}\", x);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Is `x` 10 or 100? x = 10\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Formatted print](https://www.rustwiki.org.cn/en/rust-by-example/hello/print.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Printing is handled by a series of [macros](https://www.rustwiki.org.cn/en/rust-by-example/macros.html) defined in [std::fmt](https://doc.rust-lang.org/std/fmt/) some of which include:\n",
    "\n",
    "- `format!`: write formatted text to String\n",
    "- `print!`: same as format! but the text is printed to the console (`io::stdout`).\n",
    "- `println!`: same as print! but a newline is appended.\n",
    "- `eprint!`: same as format! but the text is printed to the standard error (`io::stderr`).\n",
    "- `eprintln!`: same as eprint!but a newline is appended."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All parse text in the same fashion. As a plus, Rust checks formatting correctness at compile time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "invalid reference to positional argument 1 (there is 1 argument)",
     "output_type": "error",
     "traceback": [
      "\u001b[31mError:\u001b[0m invalid reference to positional argument 1 (there is 1 argument)",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_6:1:1\u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m31 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mM\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m0\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m0\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mB\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m error: invalid reference to positional argument 1 (there is 1 argument)",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "`Structure` doesn't implement `std::fmt::Display`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m `Structure` doesn't implement `std::fmt::Display`",
      "    \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_6:1:1\u001b[38;5;246m]\u001b[0m",
      "    \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m40 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mT\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m`\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m`\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mS\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m3\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m   │\u001b[0m                                                 \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m   │\u001b[0m                                                       \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Structure` cannot be formatted with the default formatter",
      "\u001b[38;5;246m────╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    // In general, the `{}` will be automatically replaced with any\n",
    "    // arguments. These will be stringified.\n",
    "    println!(\"{} days\", 31);\n",
    "\n",
    "    // Without a suffix, 31 becomes an i32. You can change what type 31 is\n",
    "    // by providing a suffix. The number 31i64 for example has the type i64.\n",
    "\n",
    "    // There are various optional patterns this works with. Positional\n",
    "    // arguments can be used.\n",
    "    println!(\"{0}, this is {1}. {1}, this is {0}\", \"Alice\", \"Bob\");\n",
    "\n",
    "    // As can named arguments.\n",
    "    println!(\"{subject} {verb} {object}\",\n",
    "             object=\"the lazy dog\",\n",
    "             subject=\"the quick brown fox\",\n",
    "             verb=\"jumps over\");\n",
    "\n",
    "    // Special formatting can be specified after a `:`.\n",
    "    println!(\"{} of {:b} people know binary, the other half doesn't\", 1, 2);\n",
    "\n",
    "    // You can right-align text with a specified width. This will output\n",
    "    // \"     1\". 5 white spaces and a \"1\".\n",
    "    println!(\"{number:>width$}\", number=1, width=6);\n",
    "\n",
    "    // You can pad numbers with extra zeroes. This will output \"000001\".\n",
    "    println!(\"{number:0>width$}\", number=1, width=6);\n",
    "\n",
    "    // Rust even checks to make sure the correct number of arguments are\n",
    "    // used.\n",
    "    println!(\"My name is {0}, {1} {0}\", \"Bond\");\n",
    "    // FIXME ^ Add the missing argument: \"James\"\n",
    "\n",
    "    // Create a structure named `Structure` which contains an `i32`.\n",
    "    #[allow(dead_code)]\n",
    "    struct Structure(i32);\n",
    "\n",
    "    // However, custom types such as this structure require more complicated\n",
    "    // handling. This will not work.\n",
    "    println!(\"This struct `{}` won't print...\", Structure(3));\n",
    "    // FIXME ^ Comment out this line.\n",
    "\n",
    "    // For Rust 1.58 and above, you can directly capture the argument from\n",
    "    // surrounding variable. Just like the above, this will output\n",
    "    // \"     1\". 5 white spaces and a \"1\".\n",
    "    let number: f64 = 1.0;\n",
    "    let width: usize = 6;\n",
    "    println!(\"{number:>width$}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[std::fmt](https://doc.rust-lang.org/std/fmt/) contains many [traits](https://doc.rust-lang.org/std/fmt/#formatting-traits) which govern the display of text. The base form of two important ones are listed below:\n",
    "\n",
    "- `fmt::Debug`: Uses the `{:?}` marker. Format text for debugging purposes.\n",
    "- `fmt::Display`: Uses the `{}` marker. Format text in a more elegant, user friendly fashion.\n",
    "\n",
    "Here, we used `fmt::Display` because the std library provides implementations for these types. To print text for custom types, more steps are required.\n",
    "\n",
    "Implementing the `fmt::Display` trait automatically implements the [ToString](https://doc.rust-lang.org/std/string/trait.ToString.html) trait which allows us to [convert](https://www.rustwiki.org.cn/en/rust-by-example/conversion/string.html) the type to [String](https://www.rustwiki.org.cn/en/rust-by-example/std/str.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Activities"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Fix the two issues in the above code (see FIXME) so that it runs without error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;\n",
    "\n",
    "// Create a structure named `Structure` which contains an `i32`.\n",
    "#[allow(dead_code)]\n",
    "struct Structure(i32);\n",
    "\n",
    "impl fmt::Display for Structure {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"Structure({})\", self.0)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    // In general, the `{}` will be automatically replaced with any\n",
    "    // arguments. These will be stringified.\n",
    "    println!(\"{} days\", 31);\n",
    "\n",
    "    // Without a suffix, 31 becomes an i32. You can change what type 31 is\n",
    "    // by providing a suffix. The number 31i64 for example has the type i64.\n",
    "\n",
    "    // There are various optional patterns this works with. Positional\n",
    "    // arguments can be used.\n",
    "    println!(\"{0}, this is {1}. {1}, this is {0}\", \"Alice\", \"Bob\");\n",
    "\n",
    "    // As can named arguments.\n",
    "    println!(\"{subject} {verb} {object}\",\n",
    "             object=\"the lazy dog\",\n",
    "             subject=\"the quick brown fox\",\n",
    "             verb=\"jumps over\");\n",
    "\n",
    "    // Special formatting can be specified after a `:`.\n",
    "    println!(\"{} of {:b} people know binary, the other half doesn't\", 1, 2);\n",
    "\n",
    "    // You can right-align text with a specified width. This will output\n",
    "    // \"     1\". 5 white spaces and a \"1\".\n",
    "    println!(\"{number:>width$}\", number=1, width=6);\n",
    "\n",
    "    // You can pad numbers with extra zeroes. This will output \"000001\".\n",
    "    println!(\"{number:0>width$}\", number=1, width=6);\n",
    "\n",
    "    // Rust even checks to make sure the correct number of arguments are used.\n",
    "    println!(\"My name is {0}, {1} {0}\", \"Bond\", \"James\");\n",
    "    // Fixed: Added the missing argument \"James\"\n",
    "\n",
    "    // Now this will work because we've implemented Display for Structure\n",
    "    println!(\"This struct `{}` will print!\", Structure(3));\n",
    "\n",
    "    // For Rust 1.58 and above, you can directly capture the argument from\n",
    "    // surrounding variable. Just like the above, this will output\n",
    "    // \"     1\". 5 white spaces and a \"1\".\n",
    "    let number: f64 = 1.0;\n",
    "    let width: usize = 6;\n",
    "    println!(\"{number:>width$}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "31 days\n",
      "Alice, this is Bob. Bob, this is Alice\n",
      "the quick brown fox jumps over the lazy dog\n",
      "1 of 10 people know binary, the other half doesn't\n",
      "     1\n",
      "000001\n",
      "My name is Bond, James Bond\n",
      "This struct `Structure(3)` will print!\n",
      "     1\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Add a `println!` macro call that prints: `Pi is roughly 3.142` by controlling the number of decimal places shown. For the purposes of this exercise, use `let pi = 3.141592` as an estimate for `pi`. (Hint: you may need to check the [std::fmt](https://doc.rust-lang.org/std/fmt/) documentation for setting the number of decimals to display)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let pi = 3.141592;\n",
    "    println!(\"Pi is roughly {:.3}\", pi);\n",
    "    println!(\"Pi is roughly {0:.3}\", pi);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pi is roughly 3.142\n",
      "Pi is roughly 3.142\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let pi = 3.141592;\n",
    "\n",
    "    // 1. 使用 .3 精度说明符\n",
    "    println!(\"1. Pi is roughly {:.3}\", pi);\n",
    "\n",
    "    // 2. 使用参数指定精度\n",
    "    println!(\"2. Pi is roughly {0:.1$}\", pi, 3);\n",
    "\n",
    "    // 3. 使用命名参数\n",
    "    println!(\"3. Pi is roughly {num:.prec$}\", num = pi, prec = 3);\n",
    "\n",
    "    // 4. 使用 * 动态指定精度\n",
    "    println!(\"4. Pi is roughly {:.*}\", 3, pi);\n",
    "\n",
    "    // 5. 使用位置参数和 * \n",
    "    println!(\"5. Pi is roughly {1:.*}\", 3, pi);\n",
    "\n",
    "    // 6. 结合宽度和精度\n",
    "    println!(\"6. Pi is roughly {:6.3}\", pi);\n",
    "\n",
    "    // 7. 使用填充字符和对齐\n",
    "    println!(\"7. Pi is roughly {:0>6.3}\", pi);\n",
    "\n",
    "    // 8. 使用 format! 宏创建字符串\n",
    "    let formatted_pi = format!(\"{:.3}\", pi);\n",
    "    println!(\"8. Pi is roughly {}\", formatted_pi);\n",
    "\n",
    "    // 9. 使用 format_args! 和 print! 分开\n",
    "    print!(\"9. \");\n",
    "    print!(\"{}\", format_args!(\"Pi is roughly {:.3}\\n\", pi));\n",
    "\n",
    "    // 10. 结合符号和精度\n",
    "    println!(\"10. Pi is roughly {:+.3}\", pi);\n",
    "\n",
    "    // 11. 使用科学记数法\n",
    "    println!(\"11. Pi is roughly {:.3e}\", pi);\n",
    "\n",
    "    // 12. 使用替代形式（这里没有效果，但展示了语法）\n",
    "    println!(\"12. Pi is roughly {:#.3}\", pi);\n",
    "\n",
    "    // 13. 左对齐，指定宽度\n",
    "    println!(\"13. Pi is roughly {:<10.3}\", pi);\n",
    "\n",
    "    // 14. 右对齐，指定宽度\n",
    "    println!(\"14. Pi is roughly {:>10.3}\", pi);\n",
    "\n",
    "    // 15. 居中对齐，指定宽度\n",
    "    println!(\"15. Pi is roughly {:^10.3}\", pi);\n",
    "\n",
    "    // 16. 使用自定义填充字符\n",
    "    println!(\"16. Pi is roughly {:*^10.3}\", pi);\n",
    "\n",
    "    // 17. 使用千位分隔符\n",
    "    println!(\"17. A billion pi is roughly {:.3}\", pi * 1_000_000_000.0);\n",
    "\n",
    "    // 18. 使用二进制表示（对整数有效）\n",
    "    println!(\"18. Pi as integer in binary: {:b}\", pi as i32);\n",
    "\n",
    "    // 19. 使用十六进制表示（对整数有效）\n",
    "    println!(\"19. Pi as integer in hexadecimal: {:x}\", pi as i32);\n",
    "\n",
    "    // 20. 使用指数记数法并指定大写字母\n",
    "    println!(\"20. Pi in uppercase exponential: {:.3E}\", pi);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Pi is roughly 3.142\n",
      "2. Pi is roughly 3.142\n",
      "3. Pi is roughly 3.142\n",
      "4. Pi is roughly 3.142\n",
      "5. Pi is roughly 3.142\n",
      "6. Pi is roughly  3.142\n",
      "7. Pi is roughly 03.142\n",
      "8. Pi is roughly 3.142\n",
      "9. Pi is roughly 3.142\n",
      "10. Pi is roughly +3.142\n",
      "11. Pi is roughly 3.142e0\n",
      "12. Pi is roughly 3.142\n",
      "13. Pi is roughly 3.142     \n",
      "14. Pi is roughly      3.142\n",
      "15. Pi is roughly   3.142   \n",
      "16. Pi is roughly **3.142***\n",
      "17. A billion pi is roughly 3141592000.000\n",
      "18. Pi as integer in binary: 11\n",
      "19. Pi as integer in hexadecimal: 3\n",
      "20. Pi in uppercase exponential: 3.142E0\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Debug](https://www.rustwiki.org.cn/en/rust-by-example/hello/print/print_debug.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All types which want to use `std::fmt` formatting `traits` require an implementation to be printable. Automatic implementations are only provided for types such as in the `std` library. All others *must* be manually implemented somehow.\n",
    "\n",
    "The `fmt::Debug` `trait` makes this very straightforward. *All* types can `derive` (automatically create) the `fmt::Debug` implementation. This is not true for `fmt::Display` which must be manually implemented."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "// This structure cannot be printed either with `fmt::Display` or\n",
    "// with `fmt::Debug`.\n",
    "struct UnPrintable(i32);\n",
    "\n",
    "// The `derive` attribute automatically creates the implementation\n",
    "// required to make this `struct` printable with `fmt::Debug`.\n",
    "#[derive(Debug)]\n",
    "struct DebugPrintable(i32);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Derive the `fmt::Debug` implementation for `Structure`. `Structure`\n",
    "// is a structure which contains a single `i32`.\n",
    "#[derive(Debug)]\n",
    "struct Structure(i32);\n",
    "\n",
    "// Put a `Structure` inside of the structure `Deep`. Make it printable\n",
    "// also.\n",
    "#[derive(Debug)]\n",
    "struct Deep(Structure);\n",
    "\n",
    "fn main() {\n",
    "    // Printing with `{:?}` is similar to with `{}`.\n",
    "    println!(\"{:?} months in a year.\", 12);\n",
    "    println!(\"{1:?} {0:?} is the {actor:?} name.\",\n",
    "             \"Slater\",\n",
    "             \"Christian\",\n",
    "             actor=\"actor's\");\n",
    "\n",
    "    // `Structure` is printable!\n",
    "    println!(\"Now {:?} will print!\", Structure(3));\n",
    "    \n",
    "    // The problem with `derive` is there is no control over how\n",
    "    // the results look. What if I want this to just show a `7`?\n",
    "    println!(\"Now {:?} will print!\", Deep(Structure(7)));\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "12 months in a year.\n",
      "\"Christian\" \"Slater\" is the \"actor's\" name.\n",
      "Now Structure(3) will print!\n",
      "Now Deep(Structure(7)) will print!\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So `fmt::Debug` definitely makes this printable but sacrifices some elegance. Rust also provides \"pretty printing\" with `{:#?}`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#[derive(Debug)]\n",
    "struct Person<'a> {\n",
    "    name: &'a str,\n",
    "    age: u8\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let name = \"Peter\";\n",
    "    let age = 27;\n",
    "    let peter = Person { name, age };\n",
    "\n",
    "    // Pretty print\n",
    "    println!(\"{:#?}\", peter);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Person {\n",
      "    name: \"Peter\",\n",
      "    age: 27,\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One can manually implement `fmt::Display` to control the display."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Display](https://www.rustwiki.org.cn/en/rust-by-example/hello/print/print_display.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`fmt::Debug` hardly looks compact and clean, so it is often advantageous to customize the output appearance. <br/>\n",
    "This is done by manually implementing [`fmt::Display`](https://doc.rust-lang.org/std/fmt/), which uses the `{}` print marker. Implementing it looks like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Import (via `use`) the `fmt` module to make it available.\n",
    "use std::fmt;\n",
    "\n",
    "// Define a structure for which `fmt::Display` will be implemented. This is\n",
    "// a tuple struct named `Structure` that contains an `i32`.\n",
    "struct Structure(i32);\n",
    "\n",
    "// To use the `{}` marker, the trait `fmt::Display` must be implemented\n",
    "// manually for the type.\n",
    "impl fmt::Display for Structure {\n",
    "    // This trait requires `fmt` with this exact signature.\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // Write strictly the first element into the supplied output\n",
    "        // stream: `f`. Returns `fmt::Result` which indicates whether the\n",
    "        // operation succeeded or failed. Note that `write!` uses syntax which\n",
    "        // is very similar to `println!`.\n",
    "        write!(f, \"{}\", self.0)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`fmt::Display` may be cleaner than `fmt::Debug` but this presents a problem for the `std` library. How should ambiguous types be displayed? For example, if the `std` library implemented a single style for all `Vec<T>`, what style should it be? Would it be either of these two?\n",
    "\n",
    "- `Vec<path>`: `/:/etc:/home/username:/bin` (split on `:`)\n",
    "- `Vec<number>`: `1,2,3` (split on `,`)\n",
    "\n",
    "No, because there is no ideal style for all types and the `std` library doesn't presume to dictate one. `fmt::Display` is not implemented for `Vec<T>` or for any other generic containers. `fmt::Debug` must then be used for these generic cases.\n",
    "\n",
    "This is not a problem though because for any new *container* type which is *not* generic,`fmt::Display` can be implemented."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt; // Import `fmt`\n",
    "\n",
    "// A structure holding two numbers. `Debug` will be derived so the results can\n",
    "// be contrasted with `Display`.\n",
    "#[derive(Debug)]\n",
    "struct MinMax(i64, i64);\n",
    "\n",
    "// Implement `Display` for `MinMax`.\n",
    "impl fmt::Display for MinMax {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // Use `self.number` to refer to each positional data point.\n",
    "        write!(f, \"({}, {})\", self.0, self.1)\n",
    "    }\n",
    "}\n",
    "\n",
    "// Define a structure where the fields are nameable for comparison.\n",
    "#[derive(Debug)]\n",
    "struct Point2D {\n",
    "    x: f64,\n",
    "    y: f64,\n",
    "}\n",
    "\n",
    "// Similarly, implement `Display` for `Point2D`\n",
    "impl fmt::Display for Point2D {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // Customize so only `x` and `y` are denoted.\n",
    "        write!(f, \"x: {}, y: {}\", self.x, self.y)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let minmax = MinMax(0, 14);\n",
    "\n",
    "    println!(\"Compare structures:\");\n",
    "    println!(\"Display: {}\", minmax);\n",
    "    println!(\"Debug: {:?}\", minmax);\n",
    "\n",
    "    let big_range =   MinMax(-300, 300);\n",
    "    let small_range = MinMax(-3, 3);\n",
    "\n",
    "    println!(\"The big range is {big} and the small is {small}\",\n",
    "             small = small_range,\n",
    "             big = big_range);\n",
    "\n",
    "    let point = Point2D { x: 3.3, y: 7.2 };\n",
    "\n",
    "    println!(\"Compare points:\");\n",
    "    println!(\"Display: {}\", point);\n",
    "    println!(\"Debug: {:?}\", point);\n",
    "\n",
    "    // Error. Both `Debug` and `Display` were implemented, but `{:b}`\n",
    "    // requires `fmt::Binary` to be implemented. This will not work.\n",
    "    // println!(\"What does Point2D look like in binary: {:b}?\", point);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Compare structures:\n",
      "Display: (0, 14)\n",
      "Debug: MinMax(0, 14)\n",
      "The big range is (-300, 300) and the small is (-3, 3)\n",
      "Compare points:\n",
      "Display: x: 3.3, y: 7.2\n",
      "Debug: Point2D { x: 3.3, y: 7.2 }\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "the trait bound `Point2D: Binary` is not satisfied",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m the trait bound `Point2D: Binary` is not satisfied",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_12:1:1\u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mW\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mP\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249mD\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m{\u001b[0m\u001b[38;5;100m:\u001b[0m\u001b[38;5;100mb\u001b[0m\u001b[38;5;100m}\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                                                      \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m    \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                                                        \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m required by a bound introduced by this call",
      " \u001b[38;5;240m  │\u001b[0m                                                                \u001b[38;5;54m│\u001b[0m    ",
      " \u001b[38;5;240m  │\u001b[0m                                                                \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m the trait `Binary` is not implemented for `Point2D`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: required by this bound in `Argument::<'a>::new_binary`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let point = Point2D { x: 3.3, y: 7.2 };\n",
    "\n",
    "    // Error. Both `Debug` and `Display` were implemented, but `{:b}`\n",
    "    // requires `fmt::Binary` to be implemented. This will not work.\n",
    "    println!(\"What does Point2D look like in binary: {:b}?\", point);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So, `fmt::Display` has been implemented but `fmt::Binary` has not, and therefore cannot be used. `std::fmt` has many such [`traits`](https://doc.rust-lang.org/std/fmt/#formatting-traits) and each requires its own implementation. This is detailed further in [`std::fmt`](https://doc.rust-lang.org/std/fmt/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Activity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After checking the output of the above example, use the `Point2D` struct as a guide to add a `Complex` struct to the example. When printed in the same way, the output should be:\n",
    "\n",
    "```shell\n",
    "Display: 3.3 + 7.2i\n",
    "Debug: Complex { real: 3.3, imag: 7.2 }\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Define the Point2D struct\n",
    "#[derive(Debug)]\n",
    "struct Point2D {\n",
    "    x: f64,\n",
    "    y: f64,\n",
    "}\n",
    "\n",
    "impl fmt::Display for Point2D {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"x: {}, y: {}\", self.x, self.y)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "// New Complex struct\n",
    "struct Complex {\n",
    "    real: f64,\n",
    "    imag: f64,\n",
    "}\n",
    "\n",
    "// Implement Display for Complex\n",
    "impl fmt::Display for Complex {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"{} + {}i\", self.real, self.imag)\n",
    "    }\n",
    "}\n",
    "\n",
    "// Implement Debug for Complex\n",
    "impl fmt::Debug for Complex {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        f.debug_struct(\"Complex\")\n",
    "         .field(\"real\", &self.real)\n",
    "         .field(\"imag\", &self.imag)\n",
    "         .finish()\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let point = Point2D { x: 3.3, y: 7.2 };\n",
    "    println!(\"Display: {}\", point);\n",
    "    \n",
    "    let complex = Complex { real: 3.3, imag: 7.2 };\n",
    "    println!(\"Display: {}\", complex);\n",
    "    println!(\"Debug: {:?}\", complex);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Display: x: 3.3, y: 7.2\n",
      "Display: 3.3 + 7.2i\n",
      "Debug: Complex { real: 3.3, imag: 7.2 }\n"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/E99nfnoKE\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;\n",
    "\n",
    "// Define the Point2D struct\n",
    "#[derive(Debug)]\n",
    "struct Point2D {\n",
    "    x: f64,\n",
    "    y: f64,\n",
    "}\n",
    "\n",
    "impl fmt::Display for Point2D {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"x: {}, y: {}\", self.x, self.y)\n",
    "    }\n",
    "}\n",
    "\n",
    "// New Complex struct\n",
    "#[derive(Debug)]\n",
    "struct Complex {\n",
    "    real: f64,\n",
    "    imag: f64,\n",
    "}\n",
    "\n",
    "// Implement Display for Complex\n",
    "impl fmt::Display for Complex {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        write!(f, \"{} + {}i\", self.real, self.imag)\n",
    "    }\n",
    "}\n",
    "\n",
    "// Implement Debug for Complex\n",
    "// impl fmt::Debug for Complex {\n",
    "//     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "//         f.debug_struct(\"Complex\")\n",
    "//          .field(\"real\", &self.real)\n",
    "//          .field(\"imag\", &self.imag)\n",
    "//          .finish()\n",
    "//     }\n",
    "// }\n",
    "\n",
    "fn main() {\n",
    "    let point = Point2D { x: 3.3, y: 7.2 };\n",
    "    println!(\"Display: {}\", point);\n",
    "    \n",
    "    let complex = Complex { real: 3.3, imag: 7.2 };\n",
    "    println!(\"Display: {}\", complex);\n",
    "    println!(\"Debug: {:?}\", complex);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Display: x: 3.3, y: 7.2\n",
      "Display: 3.3 + 7.2i\n",
      "Debug: Complex { real: 3.3, imag: 7.2 }\n"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/M96Pdjxne\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [Testcase: List](https://www.rustwiki.org.cn/en/rust-by-example/hello/print/print_display/testcase_list.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Implementing `fmt::Display` for a structure where the elements must each be handled sequentially is tricky. The problem is that each `write!` generates a `fmt::Result`. Proper handling of this requires dealing with *all* the results. Rust provides the `?` operator for exactly this purpose."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using `?` on `write!` looks like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot find value `f` in this scope",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0425] Error:\u001b[0m cannot find value `f` in this scope",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_2:1:1\u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mw\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m        \u001b[38;5;54m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m        \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    },
    {
     "ename": "Error",
     "evalue": "cannot find value `value` in this scope",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0425] Error:\u001b[0m cannot find value `value` in this scope",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_2:1:1\u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249mw\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m?\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                 \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// Try `write!` to see if it errors. If it errors, return\n",
    "// the error. Otherwise continue.\n",
    "write!(f, \"{}\", value)?;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With `?` available, implementing `fmt::Display` for a `Vec` is straightforward:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt; // Import the `fmt` module.\n",
    "\n",
    "// Define a structure named `List` containing a `Vec`.\n",
    "struct List(Vec<i32>);\n",
    "\n",
    "impl fmt::Display for List {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        // Extract the value using tuple indexing,\n",
    "        // and create a reference to `vec`.\n",
    "        let vec = &self.0;\n",
    "\n",
    "        write!(f, \"[\")?;\n",
    "\n",
    "        // Iterate over `v` in `vec` while enumerating the iteration\n",
    "        // count in `count`.\n",
    "        for (count, v) in vec.iter().enumerate() {\n",
    "            // For every element except the first, add a comma.\n",
    "            // Use the ? operator to return on errors.\n",
    "            if count != 0 { write!(f, \", \")?; }\n",
    "            write!(f, \"{}\", v)?;\n",
    "        }\n",
    "\n",
    "        // Close the opened bracket and return a fmt::Result value.\n",
    "        write!(f, \"]\")\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let v = List(vec![1, 2, 3]);\n",
    "    println!(\"{}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Activity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try changing the program so that the index of each element in the vector is also printed. The new output should look like this:\n",
    "\n",
    "```shell\n",
    "[0: 1, 1: 2, 2: 3]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt;\n",
    "\n",
    "struct List(Vec<i32>);\n",
    "\n",
    "impl fmt::Display for List {\n",
    "    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n",
    "        let vec = &self.0;\n",
    "\n",
    "        write!(f, \"[\")?;\n",
    "\n",
    "        for (count, v) in vec.iter().enumerate() {\n",
    "            if count != 0 { write!(f, \", \")?; }\n",
    "            write!(f, \"{}: {}\", count, v)?;\n",
    "        }\n",
    "\n",
    "        write!(f, \"]\")\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    let v = List(vec![1, 2, 3]);\n",
    "    println!(\"{}\", v);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0: 1, 1: 2, 2: 3]\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## [Formatting](https://www.rustwiki.org.cn/en/rust-by-example/hello/print/fmt.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We've seen that formatting is specified via a *format string*:\n",
    "\n",
    "- `format!(\"{}\", foo)` -> `\"3735928559\"`\n",
    "- `format!(\"0x{:X}\", foo)` -> [`\"0xDEADBEEF\"`](https://en.wikipedia.org/wiki/Deadbeef#Magic_debug_values)\n",
    "- `format!(\"0o{:o}\", foo)` -> `\"0o33653337357\"`\n",
    "\n",
    "The same variable (`foo`) can be formatted differently depending on which *argument type* is used: `X` vs `o` vs *unspecified*.\n",
    "\n",
    "This formatting functionality is implemented via traits, and there is one trait for each argument type. The most common formatting trait is `Display`, which handles cases where the argument type is left unspecified: `{}` for instance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt::{self, Formatter, Display};\n",
    "\n",
    "struct City {\n",
    "    name: &'static str,\n",
    "    // Latitude\n",
    "    lat: f32,\n",
    "    // Longitude\n",
    "    lon: f32,\n",
    "}\n",
    "\n",
    "impl Display for City {\n",
    "    // `f` is a buffer, and this method must write the formatted string into it\n",
    "    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
    "        let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };\n",
    "        let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };\n",
    "\n",
    "        // `write!` is like `format!`, but it will write the formatted string\n",
    "        // into a buffer (the first argument)\n",
    "        write!(f, \"{}: {:.3}°{} {:.3}°{}\",\n",
    "               self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)\n",
    "    }\n",
    "}\n",
    "\n",
    "#[derive(Debug)]\n",
    "struct Color {\n",
    "    red: u8,\n",
    "    green: u8,\n",
    "    blue: u8,\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    for city in [\n",
    "        City { name: \"Dublin\", lat: 53.347778, lon: -6.259722 },\n",
    "        City { name: \"Oslo\", lat: 59.95, lon: 10.75 },\n",
    "        City { name: \"Vancouver\", lat: 49.25, lon: -123.1 },\n",
    "    ].iter() {\n",
    "        println!(\"{}\", *city);\n",
    "    }\n",
    "    for color in [\n",
    "        Color { red: 128, green: 255, blue: 90 },\n",
    "        Color { red: 0, green: 3, blue: 254 },\n",
    "        Color { red: 0, green: 0, blue: 0 },\n",
    "    ].iter() {\n",
    "        // Switch this to use {} once you've added an implementation\n",
    "        // for fmt::Display.\n",
    "        println!(\"{:?}\", *color);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dublin: 53.348°N 6.260°W\n",
      "Oslo: 59.950°N 10.750°E\n",
      "Vancouver: 49.250°N 123.100°W\n",
      "Color { red: 128, green: 255, blue: 90 }\n",
      "Color { red: 0, green: 3, blue: 254 }\n",
      "Color { red: 0, green: 0, blue: 0 }\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can view a [full list of formatting traits](https://doc.rust-lang.org/std/fmt/#formatting-traits) and their argument types in the [`std::fmt`](https://doc.rust-lang.org/std/fmt/) documentation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Activity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Add an implementation of the `fmt::Display` trait for the `Color` struct above so that the output displays as:\n",
    "\n",
    "```shell\n",
    "RGB (128, 255, 90) 0x80FF5A\n",
    "RGB (0, 3, 254) 0x0003FE\n",
    "RGB (0, 0, 0) 0x000000\n",
    "```\n",
    "\n",
    "Two hints if you get stuck:\n",
    "\n",
    "- You [may need to list each color more than once](https://doc.rust-lang.org/std/fmt/#named-parameters),\n",
    "- You can [pad with zeros to a width of 2](https://doc.rust-lang.org/std/fmt/#width) with `:0>2`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "use std::fmt::{self, Formatter, Display};\n",
    "\n",
    "struct City {\n",
    "    name: &'static str,\n",
    "    lat: f32,\n",
    "    lon: f32,\n",
    "}\n",
    "\n",
    "impl Display for City {\n",
    "    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
    "        let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };\n",
    "        let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };\n",
    "\n",
    "        write!(f, \"{}: {:.3}°{} {:.3}°{}\",\n",
    "               self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)\n",
    "    }\n",
    "}\n",
    "\n",
    "struct Color {\n",
    "    red: u8,\n",
    "    green: u8,\n",
    "    blue: u8,\n",
    "}\n",
    "\n",
    "impl Display for Color {\n",
    "    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n",
    "        write!(f, \"RGB ({}, {}, {}) 0x{:02X}{:02X}{:02X}\",\n",
    "               self.red, self.green, self.blue,\n",
    "               self.red, self.green, self.blue)\n",
    "    }\n",
    "}\n",
    "\n",
    "fn main() {\n",
    "    for city in [\n",
    "        City { name: \"Dublin\", lat: 53.347778, lon: -6.259722 },\n",
    "        City { name: \"Oslo\", lat: 59.95, lon: 10.75 },\n",
    "        City { name: \"Vancouver\", lat: 49.25, lon: -123.1 },\n",
    "    ].iter() {\n",
    "        println!(\"{}\", *city);\n",
    "    }\n",
    "    for color in [\n",
    "        Color { red: 128, green: 255, blue: 90 },\n",
    "        Color { red: 0, green: 3, blue: 254 },\n",
    "        Color { red: 0, green: 0, blue: 0 },\n",
    "    ].iter() {\n",
    "        println!(\"{}\", *color);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dublin: 53.348°N 6.260°W\n",
      "Oslo: 59.950°N 10.750°E\n",
      "Vancouver: 49.250°N 123.100°W\n",
      "RGB (128, 255, 90) 0x80FF5A\n",
      "RGB (0, 3, 254) 0x0003FE\n",
      "RGB (0, 0, 0) 0x000000\n"
     ]
    }
   ],
   "source": [
    "main();"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
